using System;
using System.Runtime.InteropServices;

namespace dotGen.CustomTool.Fx
{
    public class ServiceProvider : IServiceProvider, IObjectWithSite
    {
        private static Guid IID_IUnknown = new Guid("{00000000-0000-0000-C000-000000000046}");
        private IOleServiceProvider serviceProvider;

        public ServiceProvider(IOleServiceProvider sp)
        {
            serviceProvider = sp;
        }

        public virtual void Dispose()
        {
            if (serviceProvider != null)
                serviceProvider = null;
        }

        public static bool Failed(int hr)
        {
            return hr < 0;
        }

        public virtual object GetService(Type serviceClass)
        {
            return serviceClass == null ? null : GetService(serviceClass.GUID, serviceClass);
        }

        public virtual object GetService(Guid guid)
        {
            return GetService(guid, null);
        }

        private object GetService(Guid guid, Type serviceClass)
        {
            // Valid, but wierd for caller to init us with a NULL sp
            if (serviceProvider == null)
                return null;

            object service = null;

            // No valid guid on the passed in class, so there is no service for it.
            if (guid.Equals(Guid.Empty))
                return null;

            // We provide a couple of services of our own.
            if (guid.Equals(typeof(IOleServiceProvider).GUID))
                return serviceProvider;
            if (guid.Equals(typeof(IObjectWithSite).GUID))
                return this;

            IntPtr pUnk;
            int hr = serviceProvider.QueryService(ref guid, ref IID_IUnknown, out pUnk);

            if (Succeeded(hr) && (pUnk != IntPtr.Zero))
            {
                service = Marshal.GetObjectForIUnknown(pUnk);
                Marshal.Release(pUnk);
            }

            return service;
        }

        void IObjectWithSite.GetSite(ref Guid riid, object[] ppvSite)
        {
            ppvSite[0] = GetService(riid);
        }

        void IObjectWithSite.SetSite(object pUnkSite)
        {
            if (pUnkSite is IOleServiceProvider)
                serviceProvider = (IOleServiceProvider)pUnkSite;
        }

        public static bool Succeeded(int hr)
        {
            return hr >= 0;
        }
    }
}